package at.ltasat.classifier;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;

public final class Classification<O, D> implements Iterable<Membership<D>> {
	private final O object;
	private final Membership<?>[] memberships;

	public Classification(O object, Clazz<D> clazz) {
		this(object, new Membership<?>[] { new Membership<D>(clazz, 1) });
	}

	public Classification(O object, Map<Clazz<D>, Double> memberships) {
		this(object, toArray(memberships));
	}

	private static <D> Membership<?>[] toArray(Map<Clazz<D>, Double> memberships) {
		Membership<?>[] array = new Membership<?>[memberships.size()];
		int index = 0;
		for (Clazz<D> clazz : memberships.keySet()) {
			array[index++] = new Membership<D>(clazz, memberships.get(clazz));
		}
		return array;
	}

	public Classification(O object, Membership<?>[] memberships) {
		assert object != null;
		assert memberships != null;
		assert memberships.length > 0;
		assert Membership.check(memberships);
		this.object = object;
		this.memberships = memberships.clone();
		Arrays.sort(this.memberships);
	}

	public O getObject() {
		return object;
	}

	public int getNumberOfMemberships() {
		return memberships.length;
	}

	public Clazz<D> getDominantClazz() {
		return getMembership(0).getClazz();
	}

	@SuppressWarnings("unchecked")
	public Membership<D> getMembership(int index) {
		return (Membership<D>) memberships[index];
	}

	@Override
	public Iterator<Membership<D>> iterator() {
		return new Iterator<Membership<D>>() {

			private int index;

			{
				index = 0;
			}

			@Override
			public boolean hasNext() {
				return index < memberships.length;
			}

			@Override
			public Membership<D> next() {
				return getMembership(index++);
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}

		};
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		for (int index = 0; index < getNumberOfMemberships(); index++) {
			builder.append(getMembership(index));
			builder.append(",");
		}
		return builder.toString().trim();
	}
}
